package pkev.xgrapher.common;

import pkev.xgrapher.common.entity.XFlowGraphics;
import pkev.xgrapher.component.XGrapherController;
import pkev.xgrapher.component.models.AbstractGrapherModel;
import pkev.xgrapher.transformation.AbstractTransformation;
import pkev.xgrapher.transformation.BasicTransformation;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class GrapherFactory {
    private static GrapherFactory grapherFactoryInstance = null;
    private Map<String, AbstractGrapherModel> grapherModels;
    private Map<String, ArrayList<AbstractGrapherModel>> grapherModelsDependences;
    private XGrapherController xGrapherController = null;
    private XFlowGraphics xFlowGraphicsInstance = null;
    private AbstractTransformation transformation = null;
    private Map<String, Object> sharedData;

    private GrapherFactory() {
        grapherModels = new HashMap<String, AbstractGrapherModel>();
        xGrapherController = new XGrapherController();
        transformation = new BasicTransformation();
        xFlowGraphicsInstance = new XFlowGraphics(null, transformation);
        xGrapherController.setGrapherFactory(this);
        sharedData = new HashMap<String, Object>();
        grapherModelsDependences = new HashMap<String, ArrayList<AbstractGrapherModel>>();
    }

    public static GrapherFactory getInstance() {
        if (grapherFactoryInstance == null) {
            grapherFactoryInstance = new GrapherFactory();
        }

        return grapherFactoryInstance;
    }

    public XGrapherController getXGrapherControllerInstance() {
        return xGrapherController;
    }

    private boolean isAbstractGrapherModelClass(Class c) {
        return AbstractGrapherModel.class.getCanonicalName().equals(c.getSuperclass().getCanonicalName())
                || AbstractGrapherModel.class.getCanonicalName().equals(c.getSuperclass().getSuperclass().getCanonicalName());
    }

    public ArrayList<AbstractGrapherModel> getDependences(AbstractGrapherModel model) {
        return grapherModelsDependences.get(model.getClass().getSimpleName());
    }

    public void registerGrapherModel(Class model, Class ... deps) {
        if (isAbstractGrapherModelClass(model)) {
            try {
                grapherModels.put(model.getSimpleName(), (AbstractGrapherModel) model.newInstance());
                ArrayList<AbstractGrapherModel> depsClass = new ArrayList<AbstractGrapherModel>();
                if (depsClass.size() > 0) {
                    for (Class c : deps) {
                        if (isAbstractGrapherModelClass(c)) {
                            depsClass.add((AbstractGrapherModel) c.newInstance());
                        }else{
                            throw new RuntimeException("Модель не наследует интерфейс AbstractGrapherModer!");
                        }
                    }
                }
                grapherModelsDependences.put(model.getSimpleName(), depsClass);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }else {
            throw new RuntimeException("Модель не наследует интерфейс AbstractGrapherModer!");
         }

    }

    public AbstractGrapherModel getDrawModelInstance(Class model) {
        AbstractGrapherModel instance = grapherModels.get(model.getSimpleName());
        if (instance == null) {
            throw new RuntimeException("Попытка отрисовки не зарегистрированой модели!");
        }

        return instance;
    }

    public XFlowGraphics getXFlowGraphicsInstance() {
        return xFlowGraphicsInstance;
    }

    public XFlowGraphics getXFlowGraphicsInstance(Graphics g) {
        xFlowGraphicsInstance.setG(g);
        return xFlowGraphicsInstance;
    }

    public XFlowGraphics getXFlowGraphicsInstance(Graphics g, AbstractTransformation transformation) {
        xFlowGraphicsInstance.setG(g);
        xFlowGraphicsInstance.setTransformation(transformation);
        return xFlowGraphicsInstance;
    }

    public void setTransformation(Class transClass) {
        if (AbstractTransformation.class.getCanonicalName().equals(transClass.getSuperclass().getCanonicalName())) {
            try {
                transformation = (AbstractTransformation) transClass.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }else {
            throw new RuntimeException("Базовый класс трансформации не является AbstractTransformation");
        }
    }

    public AbstractTransformation getTransformationByCustomizeRule(AbstractGrapherModel modelInstance) {
        return transformation;
    }

    public void putSharedData(String key, Object data) {
        sharedData.put(key, data);
    }

    public Object getSharedData(String key) {
        return sharedData.get(key);
    }

    public void removeSharedData(String key) {
        sharedData.remove(key);
    }
}
